#pragma once

#include "cem/boundary_condition.h"
#include "cem/electromagnetics_system.h"

#include <libmesh/dense_matrix.h>
#include <libmesh/dense_vector.h>
#include <libmesh/dof_map.h>
#include <libmesh/libmesh_common.h>
#include <libmesh/vector_value.h>
#include <libmesh/point.h>

#include <complex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <memory>

namespace cem {

// 边界条件对象基类: 负责将某一类型边界条件作用到一个单元的边界侧上。
class BoundaryConditionObject {
public:
    virtual ~BoundaryConditionObject() = default;

    // 函数: assemble_face
    // 作用: 对指定边界侧执行刚度/右端项装配（复数形式）。
    // 参数:
    //   spec - 边界规格
    //   system - 系统（用于频率、层化背景等）
    //   phif_v - 面上向量形函数
    //   jxwf - 面积分权重
    //   normals - 面法向
    //   qpoints - 积分点物理坐标
    //   n - 每变量自由度个数
    //   ke - 局部刚度矩阵（n×n，复数）
    //   fe_local - 局部右端项（n，复数）
    virtual void assemble_face(
        const BoundarySpec & spec,
        const ElectromagneticsSystem & system,
        const std::vector<std::vector<libMesh::RealVectorValue>> & phif_v,
        const std::vector<libMesh::Real> & jxwf,
        const std::vector<libMesh::Point> & normals,
        const std::vector<libMesh::Point> & qpoints,
        unsigned int n,
        libMesh::DenseMatrix<libMesh::Number> & ke,
        libMesh::DenseVector<libMesh::Number> & fe_local) const = 0;

    // 函数: accumulate_dirichlet_face
    // 作用: 对指定边界侧执行 Dirichlet(切向) 的 L2 投影累计（复数数值）。
    // 说明: 默认无操作（非 Dirichlet 类型无需实现）。
    virtual void accumulate_dirichlet_face(
        const BoundarySpec & spec,
        const ElectromagneticsSystem & system,
        const std::vector<std::vector<libMesh::RealVectorValue>> & phif_v,
        const std::vector<libMesh::Real> & jxwf,
        const std::vector<libMesh::Point> & normals,
        const std::vector<libMesh::Point> & qpoints,
        unsigned int n,
        const std::vector<libMesh::dof_id_type> & dofs,
        std::unordered_set<libMesh::dof_id_type> & dirichlet_rows_keep,
        std::unordered_map<libMesh::dof_id_type, std::complex<double>> & dirichlet_value_num,
        std::unordered_map<libMesh::dof_id_type, double> & dirichlet_value_den) const {}
};

// Neumann 条件：切向通量注入到 RHS（复数）。
class NeumannBoundaryCondition final : public BoundaryConditionObject {
public:
    void assemble_face(
        const BoundarySpec & spec,
        const ElectromagneticsSystem & system,
        const std::vector<std::vector<libMesh::RealVectorValue>> & phif_v,
        const std::vector<libMesh::Real> & jxwf,
        const std::vector<libMesh::Point> & normals,
        const std::vector<libMesh::Point> & qpoints,
        unsigned int n,
        libMesh::DenseMatrix<libMesh::Number> & ke,
        libMesh::DenseVector<libMesh::Number> & fe_local) const override;
};

// Robin 条件：alpha * (E_t, v_t) 的边界积分（复数）。
class RobinBoundaryCondition : public BoundaryConditionObject {
public:
    void assemble_face(
        const BoundarySpec & spec,
        const ElectromagneticsSystem & system,
        const std::vector<std::vector<libMesh::RealVectorValue>> & phif_v,
        const std::vector<libMesh::Real> & jxwf,
        const std::vector<libMesh::Point> & normals,
        const std::vector<libMesh::Point> & qpoints,
        unsigned int n,
        libMesh::DenseMatrix<libMesh::Number> & ke,
        libMesh::DenseVector<libMesh::Number> & fe_local) const override;
};

// 阻抗(等同于 Robin 的实现，保留单独类型以便未来扩展)。
class ImpedanceBoundaryCondition : public RobinBoundaryCondition {
public:
    void assemble_face(const BoundarySpec & spec,
                       const ElectromagneticsSystem & system,
                       const std::vector<std::vector<libMesh::RealVectorValue>> & phif_v,
                       const std::vector<libMesh::Real> & jxwf,
                       const std::vector<libMesh::Point> & normals,
                       const std::vector<libMesh::Point> & qpoints,
                       unsigned int n,
                       libMesh::DenseMatrix<libMesh::Number> & ke,
                       libMesh::DenseVector<libMesh::Number> & fe_local) const override;
};

// Dirichlet 条件：强制钉扎与 L2 投影累计（不直接改 ke/fe）。
class DirichletBoundaryCondition final : public BoundaryConditionObject {
public:
    void assemble_face(
        const BoundarySpec & /*spec*/,
        const ElectromagneticsSystem & /*system*/,
        const std::vector<std::vector<libMesh::RealVectorValue>> & /*phif_v*/,
        const std::vector<libMesh::Real> & /*jxwf*/,
        const std::vector<libMesh::Point> & /*normals*/,
        const std::vector<libMesh::Point> & /*qpoints*/,
        unsigned int /*n*/,
        libMesh::DenseMatrix<libMesh::Number> & /*ke*/,
        libMesh::DenseVector<libMesh::Number> & /*fe_local*/) const override {}

    void accumulate_dirichlet_face(
        const BoundarySpec & spec,
        const ElectromagneticsSystem & system,
        const std::vector<std::vector<libMesh::RealVectorValue>> & phif_v,
        const std::vector<libMesh::Real> & jxwf,
        const std::vector<libMesh::Point> & normals,
        const std::vector<libMesh::Point> & qpoints,
        unsigned int n,
        const std::vector<libMesh::dof_id_type> & dofs,
        std::unordered_set<libMesh::dof_id_type> & dirichlet_rows_keep,
        std::unordered_map<libMesh::dof_id_type, std::complex<double>> & dirichlet_value_num,
        std::unordered_map<libMesh::dof_id_type, double> & dirichlet_value_den) const override;
};

// 工厂: 根据边界类型创建对应的边界条件对象。
std::unique_ptr<BoundaryConditionObject>
make_boundary_condition_object(BoundaryType type);

} // namespace cem